// Platform: android
// 3.0.0-0-ge670de9
/*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at
 
     http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
*/
; (function () {
    var CORDOVA_JS_BUILD_LABEL = '3.0.0-0-ge670de9';
    // file: lib/scripts/require.js

    var require,
        define;

    (function () {
        var modules = {},
        // Stack of moduleIds currently being built.
            requireStack = [],
        // Map of module ID -> index into requireStack of modules currently being built.
            inProgressModules = {},
            SEPERATOR = ".";



        function build(module) {
            var factory = module.factory,
                localRequire = function (id) {
                    var resultantId = id;
                    //Its a relative path, so lop off the last portion and add the id (minus "./")
                    if (id.charAt(0) === ".") {
                        resultantId = module.id.slice(0, module.id.lastIndexOf(SEPERATOR)) + SEPERATOR + id.slice(2);
                    }
                    return require(resultantId);
                };
            module.exports = {};
            delete module.factory;
            factory(localRequire, module.exports, module);
            return module.exports;
        }

        require = function (id) {
            if (!modules[id]) {
                throw "module " + id + " not found";
            } else if (id in inProgressModules) {
                var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
                throw "Cycle in require graph: " + cycle;
            }
            if (modules[id].factory) {
                try {
                    inProgressModules[id] = requireStack.length;
                    requireStack.push(id);
                    return build(modules[id]);
                } finally {
                    delete inProgressModules[id];
                    requireStack.pop();
                }
            }
            return modules[id].exports;
        };

        define = function (id, factory) {
            if (modules[id]) {
                throw "module " + id + " already defined";
            }

            modules[id] = {
                id: id,
                factory: factory
            };
        };

        define.remove = function (id) {
            delete modules[id];
        };

        define.moduleMap = modules;
    })();

    //Export for use in node
    if (typeof module === "object" && typeof require === "function") {
        module.exports.require = require;
        module.exports.define = define;
    }

    // file: lib/cordova.js
    define("cordova", function (require, exports, module) {


        var channel = require('cordova/channel');

        /**
         * Listen for DOMContentLoaded and notify our channel subscribers.
         */
        document.addEventListener('DOMContentLoaded', function () {
            channel.onDOMContentLoaded.fire();
        }, false);
        if (document.readyState == 'complete' || document.readyState == 'interactive') {
            channel.onDOMContentLoaded.fire();
        }

        /**
         * Intercept calls to addEventListener + removeEventListener and handle deviceready,
         * resume, and pause events.
         */
        var m_document_addEventListener = document.addEventListener;
        var m_document_removeEventListener = document.removeEventListener;
        var m_window_addEventListener = window.addEventListener;
        var m_window_removeEventListener = window.removeEventListener;

        /**
         * Houses custom event handlers to intercept on document + window event listeners.
         */
        var documentEventHandlers = {},
            windowEventHandlers = {};

        document.addEventListener = function (evt, handler, capture) {
            var e = evt.toLowerCase();
            if (typeof documentEventHandlers[e] != 'undefined') {
                documentEventHandlers[e].subscribe(handler);
            } else {
                m_document_addEventListener.call(document, evt, handler, capture);
            }
        };

        window.addEventListener = function (evt, handler, capture) {
            var e = evt.toLowerCase();
            if (typeof windowEventHandlers[e] != 'undefined') {
                windowEventHandlers[e].subscribe(handler);
            } else {
                m_window_addEventListener.call(window, evt, handler, capture);
            }
        };

        document.removeEventListener = function (evt, handler, capture) {
            var e = evt.toLowerCase();
            // If unsubscribing from an event that is handled by a plugin
            if (typeof documentEventHandlers[e] != "undefined") {
                documentEventHandlers[e].unsubscribe(handler);
            } else {
                m_document_removeEventListener.call(document, evt, handler, capture);
            }
        };

        window.removeEventListener = function (evt, handler, capture) {
            var e = evt.toLowerCase();
            // If unsubscribing from an event that is handled by a plugin
            if (typeof windowEventHandlers[e] != "undefined") {
                windowEventHandlers[e].unsubscribe(handler);
            } else {
                m_window_removeEventListener.call(window, evt, handler, capture);
            }
        };

        function createEvent(type, data) {
            var event = document.createEvent('Events');
            event.initEvent(type, false, false);
            if (data) {
                for (var i in data) {
                    if (data.hasOwnProperty(i)) {
                        event[i] = data[i];
                    }
                }
            }
            return event;
        }

        if (typeof window.console === "undefined") {
            window.console = {
                log: function () { }
            };
        }
        // there are places in the framework where we call `warn` also, so we should make sure it exists
        if (typeof window.console.warn === "undefined") {
            window.console.warn = function (msg) {
                this.log("warn: " + msg);
            }
        }

        var cordova = {
            define: define,
            require: require,
            /**
             * Methods to add/remove your own addEventListener hijacking on document + window.
             */
            addWindowEventHandler: function (event) {
                return (windowEventHandlers[event] = channel.create(event));
            },
            addStickyDocumentEventHandler: function (event) {
                return (documentEventHandlers[event] = channel.createSticky(event));
            },
            addDocumentEventHandler: function (event) {
                return (documentEventHandlers[event] = channel.create(event));
            },
            removeWindowEventHandler: function (event) {
                delete windowEventHandlers[event];
            },
            removeDocumentEventHandler: function (event) {
                delete documentEventHandlers[event];
            },
            /**
             * Retrieve original event handlers that were replaced by Cordova
             *
             * @return object
             */
            getOriginalHandlers: function () {
                return {
                    'document': { 'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener },
                    'window': { 'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener }
                };
            },
            /**
             * Method to fire event from native code
             * bNoDetach is required for events which cause an exception which needs to be caught in native code
             */
            fireDocumentEvent: function (type, data, bNoDetach) {
                var evt = createEvent(type, data);
                if (typeof documentEventHandlers[type] != 'undefined') {
                    if (bNoDetach) {
                        documentEventHandlers[type].fire(evt);
                    }
                    else {
                        setTimeout(function () {
                            // Fire deviceready on listeners that were registered before cordova.js was loaded.
                            if (type == 'deviceready') {
                                document.dispatchEvent(evt);
                            }
                            documentEventHandlers[type].fire(evt);
                        }, 0);
                    }
                } else {
                    document.dispatchEvent(evt);
                }
            },
            fireWindowEvent: function (type, data) {
                var evt = createEvent(type, data);
                if (typeof windowEventHandlers[type] != 'undefined') {
                    setTimeout(function () {
                        windowEventHandlers[type].fire(evt);
                    }, 0);
                } else {
                    window.dispatchEvent(evt);
                }
            },

            /**
             * Plugin callback mechanism.
             */
            // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
            // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
            callbackId: Math.floor(Math.random() * 2000000000),
            callbacks: {},
            callbackStatus: {
                NO_RESULT: 0,
                OK: 1,
                CLASS_NOT_FOUND_EXCEPTION: 2,
                ILLEGAL_ACCESS_EXCEPTION: 3,
                INSTANTIATION_EXCEPTION: 4,
                MALFORMED_URL_EXCEPTION: 5,
                IO_EXCEPTION: 6,
                INVALID_ACTION: 7,
                JSON_EXCEPTION: 8,
                ERROR: 9
            },

            /**
             * Called by native code when returning successful result from an action.
             */
            callbackSuccess: function (callbackId, args) {
                try {
                    cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
                } catch (e) {
                    console.log("Error in error callback: " + callbackId + " = " + e);
                }
            },

            /**
             * Called by native code when returning error result from an action.
             */
            callbackError: function (callbackId, args) {
                // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
                // Derive success from status.
                try {
                    cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
                } catch (e) {
                    console.log("Error in error callback: " + callbackId + " = " + e);
                }
            },

            /**
             * Called by native code when returning the result from an action.
             */
            callbackFromNative: function (callbackId, success, status, args, keepCallback) {
                var callback = cordova.callbacks[callbackId];
                if (callback) {
                    if (success && status == cordova.callbackStatus.OK) {
                        callback.success && callback.success.apply(null, args);
                    } else if (!success) {
                        callback.fail && callback.fail.apply(null, args);
                    }

                    // Clear callback if not expecting any more results
                    if (!keepCallback) {
                        delete cordova.callbacks[callbackId];
                    }
                }
            },
            addConstructor: function (func) {
                channel.onCordovaReady.subscribe(function () {
                    try {
                        func();
                    } catch (e) {
                        console.log("Failed to run constructor: " + e);
                    }
                });
            }
        };

        // Register pause, resume and deviceready channels as events on document.
        channel.onPause = cordova.addDocumentEventHandler('pause');
        channel.onResume = cordova.addDocumentEventHandler('resume');
        channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');

        module.exports = cordova;

    });

    // file: lib/common/argscheck.js
    define("cordova/argscheck", function (require, exports, module) {

        var exec = require('cordova/exec');
        var utils = require('cordova/utils');

        var moduleExports = module.exports;

        var typeMap = {
            'A': 'Array',
            'D': 'Date',
            'N': 'Number',
            'S': 'String',
            'F': 'Function',
            'O': 'Object'
        };

        function extractParamName(callee, argIndex) {
            return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
        }

        function checkArgs(spec, functionName, args, opt_callee) {
            if (!moduleExports.enableChecks) {
                return;
            }
            var errMsg = null;
            var typeName;
            for (var i = 0; i < spec.length; ++i) {
                var c = spec.charAt(i),
                    cUpper = c.toUpperCase(),
                    arg = args[i];
                // Asterix means allow anything.
                if (c == '*') {
                    continue;
                }
                typeName = utils.typeName(arg);
                if ((arg === null || arg === undefined) && c == cUpper) {
                    continue;
                }
                if (typeName != typeMap[cUpper]) {
                    errMsg = 'Expected ' + typeMap[cUpper];
                    break;
                }
            }
            if (errMsg) {
                errMsg += ', but got ' + typeName + '.';
                errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
                // Don't log when running unit tests.
                if (typeof jasmine == 'undefined') {
                    console.error(errMsg);
                }
                throw TypeError(errMsg);
            }
        }

        function getValue(value, defaultValue) {
            return value === undefined ? defaultValue : value;
        }

        moduleExports.checkArgs = checkArgs;
        moduleExports.getValue = getValue;
        moduleExports.enableChecks = true;


    });

    // file: lib/common/base64.js
    define("cordova/base64", function (require, exports, module) {

        var base64 = exports;

        base64.fromArrayBuffer = function (arrayBuffer) {
            var array = new Uint8Array(arrayBuffer);
            return uint8ToBase64(array);
        };

        //------------------------------------------------------------------------------

        /* This code is based on the performance tests at http://jsperf.com/b64tests
         * This 12-bit-at-a-time algorithm was the best performing version on all
         * platforms tested.
         */

        var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var b64_12bit;

        var b64_12bitTable = function () {
            b64_12bit = [];
            for (var i = 0; i < 64; i++) {
                for (var j = 0; j < 64; j++) {
                    b64_12bit[i * 64 + j] = b64_6bit[i] + b64_6bit[j];
                }
            }
            b64_12bitTable = function () { return b64_12bit; };
            return b64_12bit;
        }

        function uint8ToBase64(rawData) {
            var numBytes = rawData.byteLength;
            var output = "";
            var segment;
            var table = b64_12bitTable();
            for (var i = 0; i < numBytes - 2; i += 3) {
                segment = (rawData[i] << 16) + (rawData[i + 1] << 8) + rawData[i + 2];
                output += table[segment >> 12];
                output += table[segment & 0xfff];
            }
            if (numBytes - i == 2) {
                segment = (rawData[i] << 16) + (rawData[i + 1] << 8);
                output += table[segment >> 12];
                output += b64_6bit[(segment & 0xfff) >> 6];
                output += '=';
            } else if (numBytes - i == 1) {
                segment = (rawData[i] << 16);
                output += table[segment >> 12];
                output += '==';
            }
            return output;
        }

    });

    // file: lib/common/builder.js
    define("cordova/builder", function (require, exports, module) {

        var utils = require('cordova/utils');

        function each(objects, func, context) {
            for (var prop in objects) {
                if (objects.hasOwnProperty(prop)) {
                    func.apply(context, [objects[prop], prop]);
                }
            }
        }

        function clobber(obj, key, value) {
            exports.replaceHookForTesting(obj, key);
            obj[key] = value;
            // Getters can only be overridden by getters.
            if (obj[key] !== value) {
                utils.defineGetter(obj, key, function () {
                    return value;
                });
            }
        }

        function assignOrWrapInDeprecateGetter(obj, key, value, message) {
            if (message) {
                utils.defineGetter(obj, key, function () {
                    console.log(message);
                    delete obj[key];
                    clobber(obj, key, value);
                    return value;
                });
            } else {
                clobber(obj, key, value);
            }
        }

        function include(parent, objects, clobber, merge) {
            each(objects, function (obj, key) {
                try {
                    var result = obj.path ? require(obj.path) : {};

                    if (clobber) {
                        // Clobber if it doesn't exist.
                        if (typeof parent[key] === 'undefined') {
                            assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
                        } else if (typeof obj.path !== 'undefined') {
                            // If merging, merge properties onto parent, otherwise, clobber.
                            if (merge) {
                                recursiveMerge(parent[key], result);
                            } else {
                                assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
                            }
                        }
                        result = parent[key];
                    } else {
                        // Overwrite if not currently defined.
                        if (typeof parent[key] == 'undefined') {
                            assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
                        } else {
                            // Set result to what already exists, so we can build children into it if they exist.
                            result = parent[key];
                        }
                    }

                    if (obj.children) {
                        include(result, obj.children, clobber, merge);
                    }
                } catch (e) {
                    utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
                }
            });
        }

        /**
         * Merge properties from one object onto another recursively.  Properties from
         * the src object will overwrite existing target property.
         *
         * @param target Object to merge properties into.
         * @param src Object to merge properties from.
         */
        function recursiveMerge(target, src) {
            for (var prop in src) {
                if (src.hasOwnProperty(prop)) {
                    if (target.prototype && target.prototype.constructor === target) {
                        // If the target object is a constructor override off prototype.
                        clobber(target.prototype, prop, src[prop]);
                    } else {
                        if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
                            recursiveMerge(target[prop], src[prop]);
                        } else {
                            clobber(target, prop, src[prop]);
                        }
                    }
                }
            }
        }

        exports.buildIntoButDoNotClobber = function (objects, target) {
            include(target, objects, false, false);
        };
        exports.buildIntoAndClobber = function (objects, target) {
            include(target, objects, true, false);
        };
        exports.buildIntoAndMerge = function (objects, target) {
            include(target, objects, true, true);
        };
        exports.recursiveMerge = recursiveMerge;
        exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
        exports.replaceHookForTesting = function () { };

    });

    // file: lib/common/channel.js
    define("cordova/channel", function (require, exports, module) {

        var utils = require('cordova/utils'),
            nextGuid = 1;

        /**
         * Custom pub-sub "channel" that can have functions subscribed to it
         * This object is used to define and control firing of events for
         * cordova initialization, as well as for custom events thereafter.
         *
         * The order of events during page load and Cordova startup is as follows:
         *
         * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
         * onNativeReady*              Internal event that indicates the Cordova native side is ready.
         * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
         * onDeviceReady*              User event fired to indicate that Cordova is ready
         * onResume                    User event fired to indicate a start/resume lifecycle event
         * onPause                     User event fired to indicate a pause lifecycle event
         * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
         *
         * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
         * All listeners that subscribe after the event is fired will be executed right away.
         *
         * The only Cordova events that user code should register for are:
         *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
         *      pause                 App has moved to background
         *      resume                App has returned to foreground
         *
         * Listeners can be registered as:
         *      document.addEventListener("deviceready", myDeviceReadyListener, false);
         *      document.addEventListener("resume", myResumeListener, false);
         *      document.addEventListener("pause", myPauseListener, false);
         *
         * The DOM lifecycle events should be used for saving and restoring state
         *      window.onload
         *      window.onunload
         *
         */

        /**
         * Channel
         * @constructor
         * @param type  String the channel name
         */
        var Channel = function (type, sticky) {
            this.type = type;
            // Map of guid -> function.
            this.handlers = {};
            // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
            this.state = sticky ? 1 : 0;
            // Used in sticky mode to remember args passed to fire().
            this.fireArgs = null;
            // Used by onHasSubscribersChange to know if there are any listeners.
            this.numHandlers = 0;
            // Function that is called when the first listener is subscribed, or when
            // the last listener is unsubscribed.
            this.onHasSubscribersChange = null;
        },
            channel = {
                /**
                 * Calls the provided function only after all of the channels specified
                 * have been fired. All channels must be sticky channels.
                 */
                join: function (h, c) {
                    var len = c.length,
                        i = len,
                        f = function () {
                            if (!(--i)) h();
                        };
                    for (var j = 0; j < len; j++) {
                        if (c[j].state === 0) {
                            throw Error('Can only use join with sticky channels.');
                        }
                        c[j].subscribe(f);
                    }
                    if (!len) h();
                },
                create: function (type) {
                    return channel[type] = new Channel(type, false);
                },
                createSticky: function (type) {
                    return channel[type] = new Channel(type, true);
                },

                /**
                 * cordova Channels that must fire before "deviceready" is fired.
                 */
                deviceReadyChannelsArray: [],
                deviceReadyChannelsMap: {},

                /**
                 * Indicate that a feature needs to be initialized before it is ready to be used.
                 * This holds up Cordova's "deviceready" event until the feature has been initialized
                 * and Cordova.initComplete(feature) is called.
                 *
                 * @param feature {String}     The unique feature name
                 */
                waitForInitialization: function (feature) {
                    if (feature) {
                        var c = channel[feature] || this.createSticky(feature);
                        this.deviceReadyChannelsMap[feature] = c;
                        this.deviceReadyChannelsArray.push(c);
                    }
                },

                /**
                 * Indicate that initialization code has completed and the feature is ready to be used.
                 *
                 * @param feature {String}     The unique feature name
                 */
                initializationComplete: function (feature) {
                    var c = this.deviceReadyChannelsMap[feature];
                    if (c) {
                        c.fire();
                    }
                }
            };

        function forceFunction(f) {
            if (typeof f != 'function') throw "Function required as first argument!";
        }

        /**
         * Subscribes the given function to the channel. Any time that
         * Channel.fire is called so too will the function.
         * Optionally specify an execution context for the function
         * and a guid that can be used to stop subscribing to the channel.
         * Returns the guid.
         */
        Channel.prototype.subscribe = function (f, c) {
            // need a function to call
            forceFunction(f);
            if (this.state == 2) {
                f.apply(c || this, this.fireArgs);
                return;
            }

            var func = f,
                guid = f.observer_guid;
            if (typeof c == "object") { func = utils.close(c, f); }

            if (!guid) {
                // first time any channel has seen this subscriber
                guid = '' + nextGuid++;
            }
            func.observer_guid = guid;
            f.observer_guid = guid;

            // Don't add the same handler more than once.
            if (!this.handlers[guid]) {
                this.handlers[guid] = func;
                this.numHandlers++;
                if (this.numHandlers == 1) {
                    this.onHasSubscribersChange && this.onHasSubscribersChange();
                }
            }
        };

        /**
         * Unsubscribes the function with the given guid from the channel.
         */
        Channel.prototype.unsubscribe = function (f) {
            // need a function to unsubscribe
            forceFunction(f);

            var guid = f.observer_guid,
                handler = this.handlers[guid];
            if (handler) {
                delete this.handlers[guid];
                this.numHandlers--;
                if (this.numHandlers === 0) {
                    this.onHasSubscribersChange && this.onHasSubscribersChange();
                }
            }
        };

        /**
         * Calls all functions subscribed to this channel.
         */
        Channel.prototype.fire = function (e) {
            var fail = false,
                fireArgs = Array.prototype.slice.call(arguments);
            // Apply stickiness.
            if (this.state == 1) {
                this.state = 2;
                this.fireArgs = fireArgs;
            }
            if (this.numHandlers) {
                // Copy the values first so that it is safe to modify it from within
                // callbacks.
                var toCall = [];
                for (var item in this.handlers) {
                    toCall.push(this.handlers[item]);
                }
                for (var i = 0; i < toCall.length; ++i) {
                    toCall[i].apply(this, fireArgs);
                }
                if (this.state == 2 && this.numHandlers) {
                    this.numHandlers = 0;
                    this.handlers = {};
                    this.onHasSubscribersChange && this.onHasSubscribersChange();
                }
            }
        };


        // defining them here so they are ready super fast!
        // DOM event that is received when the web page is loaded and parsed.
        channel.createSticky('onDOMContentLoaded');

        // Event to indicate the Cordova native side is ready.
        channel.createSticky('onNativeReady');

        // Event to indicate that all Cordova JavaScript objects have been created
        // and it's time to run plugin constructors.
        channel.createSticky('onCordovaReady');

        // Event to indicate that all automatically loaded JS plugins are loaded and ready.
        channel.createSticky('onPluginsReady');

        // Event to indicate that Cordova is ready
        channel.createSticky('onDeviceReady');

        // Event to indicate a resume lifecycle event
        channel.create('onResume');

        // Event to indicate a pause lifecycle event
        channel.create('onPause');

        // Event to indicate a destroy lifecycle event
        channel.createSticky('onDestroy');

        // Channels that must fire before "deviceready" is fired.
        channel.waitForInitialization('onCordovaReady');
        channel.waitForInitialization('onDOMContentLoaded');

        module.exports = channel;

    });

    // file: lib/common/commandProxy.js
    define("cordova/commandProxy", function (require, exports, module) {


        // internal map of proxy function
        var CommandProxyMap = {};

        module.exports = {

            // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
            add: function (id, proxyObj) {
                console.log("adding proxy for " + id);
                CommandProxyMap[id] = proxyObj;
                return proxyObj;
            },

            // cordova.commandProxy.remove("Accelerometer");
            remove: function (id) {
                var proxy = CommandProxyMap[id];
                delete CommandProxyMap[id];
                CommandProxyMap[id] = null;
                return proxy;
            },

            get: function (service, action) {
                return (CommandProxyMap[service] ? CommandProxyMap[service][action] : null);
            }
        };
    });

    // file: lib/android/exec.js
    define("cordova/exec", function (require, exports, module) {

        /**
         * Execute a cordova command.  It is up to the native side whether this action
         * is synchronous or asynchronous.  The native side can return:
         *      Synchronous: PluginResult object as a JSON string
         *      Asynchronous: Empty string ""
         * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
         * depending upon the result of the action.
         *
         * @param {Function} success    The success callback
         * @param {Function} fail       The fail callback
         * @param {String} service      The name of the service to use
         * @param {String} action       Action to be run in cordova
         * @param {String[]} [args]     Zero or more arguments to pass to the method
         */
        var cordova = require('cordova'),
            nativeApiProvider = require('cordova/plugin/android/nativeapiprovider'),
            utils = require('cordova/utils'),
            base64 = require('cordova/base64'),
            jsToNativeModes = {
                PROMPT: 0,
                JS_OBJECT: 1,
                // This mode is currently for benchmarking purposes only. It must be enabled
                // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
                // constant within CordovaWebViewClient.java before it will work.
                LOCATION_CHANGE: 2
            },
            nativeToJsModes = {
                // Polls for messages using the JS->Native bridge.
                POLLING: 0,
                // For LOAD_URL to be viable, it would need to have a work-around for
                // the bug where the soft-keyboard gets dismissed when a message is sent.
                LOAD_URL: 1,
                // For the ONLINE_EVENT to be viable, it would need to intercept all event
                // listeners (both through addEventListener and window.ononline) as well
                // as set the navigator property itself.
                ONLINE_EVENT: 2,
                // Uses reflection to access private APIs of the WebView that can send JS
                // to be executed.
                // Requires Android 3.2.4 or above.
                PRIVATE_API: 3
            },
            jsToNativeBridgeMode,  // Set lazily.
            nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
            pollEnabled = false,
            messagesFromNative = [];

        function androidExec(success, fail, service, action, args) {
            // Set default bridge modes if they have not already been set.
            // By default, we use the failsafe, since addJavascriptInterface breaks too often
            if (jsToNativeBridgeMode === undefined) {
                androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
            }

            // Process any ArrayBuffers in the args into a string.
            for (var i = 0; i < args.length; i++) {
                if (utils.typeName(args[i]) == 'ArrayBuffer') {
                    args[i] = base64.fromArrayBuffer(args[i]);
                }
            }

            var callbackId = service + cordova.callbackId++,
                argsJson = JSON.stringify(args);

            if (success || fail) {
                cordova.callbacks[callbackId] = { success: success, fail: fail };
            }

            if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
                window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
            } else {
                var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
                // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
                // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
                if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
                    androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
                    androidExec(success, fail, service, action, args);
                    androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
                    return;
                } else {
                    androidExec.processMessages(messages);
                }
            }
        }

        function pollOnce() {
            var msg = nativeApiProvider.get().retrieveJsMessages();
            androidExec.processMessages(msg);
        }

        function pollingTimerFunc() {
            if (pollEnabled) {
                pollOnce();
                setTimeout(pollingTimerFunc, 50);
            }
        }

        function hookOnlineApis() {
            function proxyEvent(e) {
                cordova.fireWindowEvent(e.type);
            }
            // The network module takes care of firing online and offline events.
            // It currently fires them only on document though, so we bridge them
            // to window here (while first listening for exec()-releated online/offline
            // events).
            window.addEventListener('online', pollOnce, false);
            window.addEventListener('offline', pollOnce, false);
            cordova.addWindowEventHandler('online');
            cordova.addWindowEventHandler('offline');
            document.addEventListener('online', proxyEvent, false);
            document.addEventListener('offline', proxyEvent, false);
        }

        hookOnlineApis();

        androidExec.jsToNativeModes = jsToNativeModes;
        androidExec.nativeToJsModes = nativeToJsModes;

        androidExec.setJsToNativeBridgeMode = function (mode) {
            if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
                console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
                mode = jsToNativeModes.PROMPT;
            }
            nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
            jsToNativeBridgeMode = mode;
        };

        androidExec.setNativeToJsBridgeMode = function (mode) {
            if (mode == nativeToJsBridgeMode) {
                return;
            }
            if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
                pollEnabled = false;
            }

            nativeToJsBridgeMode = mode;
            // Tell the native side to switch modes.
            nativeApiProvider.get().setNativeToJsBridgeMode(mode);

            if (mode == nativeToJsModes.POLLING) {
                pollEnabled = true;
                setTimeout(pollingTimerFunc, 1);
            }
        };

        // Processes a single message, as encoded by NativeToJsMessageQueue.java.
        function processMessage(message) {
            try {
                var firstChar = message.charAt(0);
                if (firstChar == 'J') {
                    eval(message.slice(1));
                } else if (firstChar == 'S' || firstChar == 'F') {
                    var success = firstChar == 'S';
                    var keepCallback = message.charAt(1) == '1';
                    var spaceIdx = message.indexOf(' ', 2);
                    var status = +message.slice(2, spaceIdx);
                    var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
                    var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
                    var payloadKind = message.charAt(nextSpaceIdx + 1);
                    var payload;
                    if (payloadKind == 's') {
                        payload = message.slice(nextSpaceIdx + 2);
                    } else if (payloadKind == 't') {
                        payload = true;
                    } else if (payloadKind == 'f') {
                        payload = false;
                    } else if (payloadKind == 'N') {
                        payload = null;
                    } else if (payloadKind == 'n') {
                        payload = +message.slice(nextSpaceIdx + 2);
                    } else if (payloadKind == 'A') {
                        var data = message.slice(nextSpaceIdx + 2);
                        var bytes = window.atob(data);
                        var arraybuffer = new Uint8Array(bytes.length);
                        for (var i = 0; i < bytes.length; i++) {
                            arraybuffer[i] = bytes.charCodeAt(i);
                        }
                        payload = arraybuffer.buffer;
                    } else if (payloadKind == 'S') {
                        payload = window.atob(message.slice(nextSpaceIdx + 2));
                    } else {
                        payload = JSON.parse(message.slice(nextSpaceIdx + 1));
                    }
                    cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
                } else {
                    console.log("processMessage failed: invalid message:" + message);
                }
            } catch (e) {
                console.log("processMessage failed: Message: " + message);
                console.log("processMessage failed: Error: " + e);
                console.log("processMessage failed: Stack: " + e.stack);
            }
        }

        // This is called from the NativeToJsMessageQueue.java.
        androidExec.processMessages = function (messages) {
            if (messages) {
                messagesFromNative.push(messages);
                // Check for the reentrant case, and enqueue the message if that's the case.
                if (messagesFromNative.length > 1) {
                    return;
                }
                while (messagesFromNative.length) {
                    // Don't unshift until the end so that reentrancy can be detected.
                    messages = messagesFromNative[0];
                    // The Java side can send a * message to indicate that it
                    // still has messages waiting to be retrieved.
                    if (messages == '*') {
                        messagesFromNative.shift();
                        window.setTimeout(pollOnce, 0);
                        return;
                    }

                    var spaceIdx = messages.indexOf(' ');
                    var msgLen = +messages.slice(0, spaceIdx);
                    var message = messages.substr(spaceIdx + 1, msgLen);
                    messages = messages.slice(spaceIdx + msgLen + 1);
                    processMessage(message);
                    if (messages) {
                        messagesFromNative[0] = messages;
                    } else {
                        messagesFromNative.shift();
                    }
                }
            }
        };

        module.exports = androidExec;

    });

    // file: lib/common/modulemapper.js
    define("cordova/modulemapper", function (require, exports, module) {

        var builder = require('cordova/builder'),
            moduleMap = define.moduleMap,
            symbolList,
            deprecationMap;

        exports.reset = function () {
            symbolList = [];
            deprecationMap = {};
        };

        function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
            if (!(moduleName in moduleMap)) {
                throw new Error('Module ' + moduleName + ' does not exist.');
            }
            symbolList.push(strategy, moduleName, symbolPath);
            if (opt_deprecationMessage) {
                deprecationMap[symbolPath] = opt_deprecationMessage;
            }
        }

        // Note: Android 2.3 does have Function.bind().
        exports.clobbers = function (moduleName, symbolPath, opt_deprecationMessage) {
            addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
        };

        exports.merges = function (moduleName, symbolPath, opt_deprecationMessage) {
            addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
        };

        exports.defaults = function (moduleName, symbolPath, opt_deprecationMessage) {
            addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
        };

        exports.runs = function (moduleName) {
            addEntry('r', moduleName, null);
        };

        function prepareNamespace(symbolPath, context) {
            if (!symbolPath) {
                return context;
            }
            var parts = symbolPath.split('.');
            var cur = context;
            for (var i = 0, part; part = parts[i]; ++i) {
                cur = cur[part] = cur[part] || {};
            }
            return cur;
        }

        exports.mapModules = function (context) {
            var origSymbols = {};
            context.CDV_origSymbols = origSymbols;
            for (var i = 0, len = symbolList.length; i < len; i += 3) {
                var strategy = symbolList[i];
                var moduleName = symbolList[i + 1];
                var module = require(moduleName);
                // <runs/>
                if (strategy == 'r') {
                    continue;
                }
                var symbolPath = symbolList[i + 2];
                var lastDot = symbolPath.lastIndexOf('.');
                var namespace = symbolPath.substr(0, lastDot);
                var lastName = symbolPath.substr(lastDot + 1);

                var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
                var parentObj = prepareNamespace(namespace, context);
                var target = parentObj[lastName];

                if (strategy == 'm' && target) {
                    builder.recursiveMerge(target, module);
                } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
                    if (!(symbolPath in origSymbols)) {
                        origSymbols[symbolPath] = target;
                    }
                    builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
                }
            }
        };

        exports.getOriginalSymbol = function (context, symbolPath) {
            var origSymbols = context.CDV_origSymbols;
            if (origSymbols && (symbolPath in origSymbols)) {
                return origSymbols[symbolPath];
            }
            var parts = symbolPath.split('.');
            var obj = context;
            for (var i = 0; i < parts.length; ++i) {
                obj = obj && obj[parts[i]];
            }
            return obj;
        };

        exports.loadMatchingModules = function (matchingRegExp) {
            for (var k in moduleMap) {
                if (matchingRegExp.exec(k)) {
                    require(k);
                }
            }
        };

        exports.reset();


    });

    // file: lib/android/platform.js
    define("cordova/platform", function (require, exports, module) {

        module.exports = {
            id: "android",
            initialize: function () {
                var channel = require("cordova/channel"),
                    cordova = require('cordova'),
                    exec = require('cordova/exec'),
                    modulemapper = require('cordova/modulemapper');

                modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
                modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');

                modulemapper.mapModules(window);

                // Inject a listener for the backbutton on the document.
                var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
                backButtonChannel.onHasSubscribersChange = function () {
                    // If we just attached the first handler or detached the last handler,
                    // let native know we need to override the back button.
                    exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
                };

                // Add hardware MENU and SEARCH button handlers
                cordova.addDocumentEventHandler('menubutton');
                cordova.addDocumentEventHandler('searchbutton');

                // Let native code know we are all done on the JS side.
                // Native code will then un-hide the WebView.
                channel.join(function () {
                    exec(null, null, "App", "show", []);
                }, [channel.onCordovaReady]);
            }
        };

    });

    // file: lib/android/plugin/android/app.js
    define("cordova/plugin/android/app", function (require, exports, module) {

        var exec = require('cordova/exec');

        module.exports = {
            /**
             * Clear the resource cache.
             */
            clearCache: function () {
                exec(null, null, "App", "clearCache", []);
            },

            /**
             * Load the url into the webview or into new browser instance.
             *
             * @param url           The URL to load
             * @param props         Properties that can be passed in to the activity:
             *      wait: int                           => wait msec before loading URL
             *      loadingDialog: "Title,Message"      => display a native loading dialog
             *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
             *      clearHistory: boolean              => clear webview history (default=false)
             *      openExternal: boolean              => open in a new browser (default=false)
             *
             * Example:
             *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
             */
            loadUrl: function (url, props) {
                exec(null, null, "App", "loadUrl", [url, props]);
            },

            /**
             * Cancel loadUrl that is waiting to be loaded.
             */
            cancelLoadUrl: function () {
                exec(null, null, "App", "cancelLoadUrl", []);
            },

            /**
             * Clear web history in this web view.
             * Instead of BACK button loading the previous web page, it will exit the app.
             */
            clearHistory: function () {
                exec(null, null, "App", "clearHistory", []);
            },

            /**
             * Go to previous page displayed.
             * This is the same as pressing the backbutton on Android device.
             */
            backHistory: function () {
                exec(null, null, "App", "backHistory", []);
            },

            /**
             * Override the default behavior of the Android back button.
             * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
             *
             * Note: The user should not have to call this method.  Instead, when the user
             *       registers for the "backbutton" event, this is automatically done.
             *
             * @param override        T=override, F=cancel override
             */
            overrideBackbutton: function (override) {
                exec(null, null, "App", "overrideBackbutton", [override]);
            },

            /**
             * Exit and terminate the application.
             */
            exitApp: function () {
                return exec(null, null, "App", "exitApp", []);
            }
        };

    });

    // file: lib/android/plugin/android/nativeapiprovider.js
    define("cordova/plugin/android/nativeapiprovider", function (require, exports, module) {

        /**
         * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
         */

        var nativeApi = this._cordovaNative || require('cordova/plugin/android/promptbasednativeapi');
        var currentApi = nativeApi;

        module.exports = {
            get: function () { return currentApi; },
            setPreferPrompt: function (value) {
                currentApi = value ? require('cordova/plugin/android/promptbasednativeapi') : nativeApi;
            },
            // Used only by tests.
            set: function (value) {
                currentApi = value;
            }
        };

    });

    // file: lib/android/plugin/android/promptbasednativeapi.js
    define("cordova/plugin/android/promptbasednativeapi", function (require, exports, module) {

        /**
         * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
         * This is used only on the 2.3 simulator, where addJavascriptInterface() is broken.
         */

        module.exports = {
            exec: function (service, action, callbackId, argsJson) {
                return prompt(argsJson, 'gap:' + JSON.stringify([service, action, callbackId]));
            },
            setNativeToJsBridgeMode: function (value) {
                prompt(value, 'gap_bridge_mode:');
            },
            retrieveJsMessages: function () {
                return prompt('', 'gap_poll:');
            }
        };

    });

    // file: lib/android/plugin/android/storage.js
    define("cordova/plugin/android/storage", function (require, exports, module) {

        var utils = require('cordova/utils'),
            exec = require('cordova/exec'),
            channel = require('cordova/channel');

        var queryQueue = {};

        /**
         * SQL result set object
         * PRIVATE METHOD
         * @constructor
         */
        var DroidDB_Rows = function () {
            this.resultSet = [];    // results array
            this.length = 0;        // number of rows
        };

        /**
         * Get item from SQL result set
         *
         * @param row           The row number to return
         * @return              The row object
         */
        DroidDB_Rows.prototype.item = function (row) {
            return this.resultSet[row];
        };

        /**
         * SQL result set that is returned to user.
         * PRIVATE METHOD
         * @constructor
         */
        var DroidDB_Result = function () {
            this.rows = new DroidDB_Rows();
        };

        /**
         * Callback from native code when query is complete.
         * PRIVATE METHOD
         *
         * @param id   Query id
         */
        function completeQuery(id, data) {
            var query = queryQueue[id];
            if (query) {
                try {
                    delete queryQueue[id];

                    // Get transaction
                    var tx = query.tx;

                    // If transaction hasn't failed
                    // Note: We ignore all query results if previous query
                    //       in the same transaction failed.
                    if (tx && tx.queryList[id]) {

                        // Save query results
                        var r = new DroidDB_Result();
                        r.rows.resultSet = data;
                        r.rows.length = data.length;
                        try {
                            if (typeof query.successCallback === 'function') {
                                query.successCallback(query.tx, r);
                            }
                        } catch (ex) {
                            console.log("executeSql error calling user success callback: " + ex);
                        }

                        tx.queryComplete(id);
                    }
                } catch (e) {
                    console.log("executeSql error: " + e);
                }
            }
        }

        /**
         * Callback from native code when query fails
         * PRIVATE METHOD
         *
         * @param reason            Error message
         * @param id                Query id
         */
        function failQuery(reason, id) {
            var query = queryQueue[id];
            if (query) {
                try {
                    delete queryQueue[id];

                    // Get transaction
                    var tx = query.tx;

                    // If transaction hasn't failed
                    // Note: We ignore all query results if previous query
                    //       in the same transaction failed.
                    if (tx && tx.queryList[id]) {
                        tx.queryList = {};

                        try {
                            if (typeof query.errorCallback === 'function') {
                                query.errorCallback(query.tx, reason);
                            }
                        } catch (ex) {
                            console.log("executeSql error calling user error callback: " + ex);
                        }

                        tx.queryFailed(id, reason);
                    }

                } catch (e) {
                    console.log("executeSql error: " + e);
                }
            }
        }

        /**
         * SQL query object
         * PRIVATE METHOD
         *
         * @constructor
         * @param tx                The transaction object that this query belongs to
         */
        var DroidDB_Query = function (tx) {

            // Set the id of the query
            this.id = utils.createUUID();

            // Add this query to the queue
            queryQueue[this.id] = this;

            // Init result
            this.resultSet = [];

            // Set transaction that this query belongs to
            this.tx = tx;

            // Add this query to transaction list
            this.tx.queryList[this.id] = this;

            // Callbacks
            this.successCallback = null;
            this.errorCallback = null;

        };

        /**
         * Transaction object
         * PRIVATE METHOD
         * @constructor
         */
        var DroidDB_Tx = function () {

            // Set the id of the transaction
            this.id = utils.createUUID();

            // Callbacks
            this.successCallback = null;
            this.errorCallback = null;

            // Query list
            this.queryList = {};
        };

        /**
         * Mark query in transaction as complete.
         * If all queries are complete, call the user's transaction success callback.
         *
         * @param id                Query id
         */
        DroidDB_Tx.prototype.queryComplete = function (id) {
            delete this.queryList[id];

            // If no more outstanding queries, then fire transaction success
            if (this.successCallback) {
                var count = 0;
                var i;
                for (i in this.queryList) {
                    if (this.queryList.hasOwnProperty(i)) {
                        count++;
                    }
                }
                if (count === 0) {
                    try {
                        this.successCallback();
                    } catch (e) {
                        console.log("Transaction error calling user success callback: " + e);
                    }
                }
            }
        };

        /**
         * Mark query in transaction as failed.
         *
         * @param id                Query id
         * @param reason            Error message
         */
        DroidDB_Tx.prototype.queryFailed = function (id, reason) {

            // The sql queries in this transaction have already been run, since
            // we really don't have a real transaction implemented in native code.
            // However, the user callbacks for the remaining sql queries in transaction
            // will not be called.
            this.queryList = {};

            if (this.errorCallback) {
                try {
                    this.errorCallback(reason);
                } catch (e) {
                    console.log("Transaction error calling user error callback: " + e);
                }
            }
        };

        /**
         * Execute SQL statement
         *
         * @param sql                   SQL statement to execute
         * @param params                Statement parameters
         * @param successCallback       Success callback
         * @param errorCallback         Error callback
         */
        DroidDB_Tx.prototype.executeSql = function (sql, params, successCallback, errorCallback) {

            // Init params array
            if (typeof params === 'undefined') {
                params = [];
            }

            // Create query and add to queue
            var query = new DroidDB_Query(this);
            queryQueue[query.id] = query;

            // Save callbacks
            query.successCallback = successCallback;
            query.errorCallback = errorCallback;

            // Call native code
            exec(null, null, "Storage", "executeSql", [sql, params, query.id]);
        };

        var DatabaseShell = function () {
        };

        /**
         * Start a transaction.
         * Does not support rollback in event of failure.
         *
         * @param process {Function}            The transaction function
         * @param successCallback {Function}
         * @param errorCallback {Function}
         */
        DatabaseShell.prototype.transaction = function (process, errorCallback, successCallback) {
            var tx = new DroidDB_Tx();
            tx.successCallback = successCallback;
            tx.errorCallback = errorCallback;
            try {
                process(tx);
            } catch (e) {
                console.log("Transaction error: " + e);
                if (tx.errorCallback) {
                    try {
                        tx.errorCallback(e);
                    } catch (ex) {
                        console.log("Transaction error calling user error callback: " + e);
                    }
                }
            }
        };

        /**
         * Open database
         *
         * @param name              Database name
         * @param version           Database version
         * @param display_name      Database display name
         * @param size              Database size in bytes
         * @return                  Database object
         */
        var DroidDB_openDatabase = function (name, version, display_name, size) {
            exec(null, null, "Storage", "openDatabase", [name, version, display_name, size]);
            var db = new DatabaseShell();
            return db;
        };


        module.exports = {
            openDatabase: DroidDB_openDatabase,
            failQuery: failQuery,
            completeQuery: completeQuery
        };

    });

    // file: lib/android/plugin/android/storage/openDatabase.js
    define("cordova/plugin/android/storage/openDatabase", function (require, exports, module) {


        var modulemapper = require('cordova/modulemapper'),
            storage = require('cordova/plugin/android/storage');

        var originalOpenDatabase = modulemapper.getOriginalSymbol(window, 'openDatabase');

        module.exports = function (name, version, desc, size) {
            // First patch WebSQL if necessary
            if (!originalOpenDatabase) {
                // Not defined, create an openDatabase function for all to use!
                return storage.openDatabase.apply(this, arguments);
            }

            // Defined, but some Android devices will throw a SECURITY_ERR -
            // so we wrap the whole thing in a try-catch and shim in our own
            // if the device has Android bug 16175.
            try {
                return originalOpenDatabase(name, version, desc, size);
            } catch (ex) {
                if (ex.code !== 18) {
                    throw ex;
                }
            }
            return storage.openDatabase(name, version, desc, size);
        };



    });

    // file: lib/android/plugin/android/storage/symbols.js
    define("cordova/plugin/android/storage/symbols", function (require, exports, module) {


        var modulemapper = require('cordova/modulemapper');

        modulemapper.clobbers('cordova/plugin/android/storage/openDatabase', 'openDatabase');


    });

    // file: lib/common/plugin/echo.js
    define("cordova/plugin/echo", function (require, exports, module) {

        var exec = require('cordova/exec'),
            utils = require('cordova/utils');

        /**
         * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
         * @param successCallback  invoked with a FileSystem object
         * @param errorCallback  invoked if error occurs retrieving file system
         * @param message  The string to be echoed.
         * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
         */
        module.exports = function (successCallback, errorCallback, message, forceAsync) {
            var action = 'echo';
            var messageIsMultipart = (utils.typeName(message) == "Array");
            var args = messageIsMultipart ? message : [message];

            if (utils.typeName(message) == 'ArrayBuffer') {
                if (forceAsync) {
                    console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.');
                }
                action += 'ArrayBuffer';
            } else if (messageIsMultipart) {
                if (forceAsync) {
                    console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.');
                }
                action += 'MultiPart';
            } else if (forceAsync) {
                action += 'Async';
            }

            exec(successCallback, errorCallback, "Echo", action, args);
        };


    });

    // file: lib/common/pluginloader.js
    define("cordova/pluginloader", function (require, exports, module) {

        var channel = require('cordova/channel');
        var modulemapper = require('cordova/modulemapper');

        // Helper function to inject a <script> tag.
        function injectScript(url, onload, onerror) {
            var script = document.createElement("script");
            // onload fires even when script fails loads with an error.
            script.onload = onload;
            script.onerror = onerror || onload;
            script.src = url;
            document.head.appendChild(script);
        }

        function onScriptLoadingComplete(moduleList) {
            // Loop through all the plugins and then through their clobbers and merges.
            for (var i = 0, module; module = moduleList[i]; i++) {
                if (module) {
                    try {
                        if (module.clobbers && module.clobbers.length) {
                            for (var j = 0; j < module.clobbers.length; j++) {
                                modulemapper.clobbers(module.id, module.clobbers[j]);
                            }
                        }

                        if (module.merges && module.merges.length) {
                            for (var k = 0; k < module.merges.length; k++) {
                                modulemapper.merges(module.id, module.merges[k]);
                            }
                        }

                        // Finally, if runs is truthy we want to simply require() the module.
                        // This can be skipped if it had any merges or clobbers, though,
                        // since the mapper will already have required the module.
                        if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
                            modulemapper.runs(module.id);
                        }
                    }
                    catch (err) {
                        // error with module, most likely clobbers, should we continue?
                    }
                }
            }

            finishPluginLoading();
        }

        // Called when:
        // * There are plugins defined and all plugins are finished loading.
        // * There are no plugins to load.
        function finishPluginLoading() {
            channel.onPluginsReady.fire();
        }

        // Handler for the cordova_plugins.js content.
        // See plugman's plugin_loader.js for the details of this object.
        // This function is only called if the really is a plugins array that isn't empty.
        // Otherwise the onerror response handler will just call finishPluginLoading().
        function handlePluginsObject(path, moduleList) {
            // Now inject the scripts.
            var scriptCounter = moduleList.length;

            if (!scriptCounter) {
                finishPluginLoading();
                return;
            }
            function scriptLoadedCallback() {
                if (!--scriptCounter) {
                    onScriptLoadingComplete(moduleList);
                }
            }

            for (var i = 0; i < moduleList.length; i++) {
                injectScript(path + moduleList[i].file, scriptLoadedCallback);
            }
        }

        function injectPluginScript(pathPrefix) {
            injectScript(pathPrefix + 'cordova_plugins.js', function () {
                try {
                    var moduleList = require("cordova/plugin_list");
                    handlePluginsObject(pathPrefix, moduleList);
                } catch (e) {
                    // Error loading cordova_plugins.js, file not found or something
                    // this is an acceptable error, pre-3.0.0, so we just move on.
                    finishPluginLoading();
                }
            }, finishPluginLoading); // also, add script load error handler for file not found
        }

        function findCordovaPath() {
            var path = null;
            var scripts = document.getElementsByTagName('script');
            var term = 'cordova.js';
            for (var n = scripts.length - 1; n > -1; n--) {
                var src = scripts[n].src;
                if (src.indexOf(term) == (src.length - term.length)) {
                    path = src.substring(0, src.length - term.length);
                    break;
                }
            }
            return path;
        }

        // Tries to load all plugins' js-modules.
        // This is an async process, but onDeviceReady is blocked on onPluginsReady.
        // onPluginsReady is fired when there are no plugins to load, or they are all done.
        exports.load = function () {
            var pathPrefix = findCordovaPath();
            if (pathPrefix === null) {
                console.log('Could not find cordova.js script tag. Plugin loading may fail.');
                pathPrefix = '';
            }
            injectPluginScript(pathPrefix);
        };


    });

    // file: lib/common/symbols.js
    define("cordova/symbols", function (require, exports, module) {

        var modulemapper = require('cordova/modulemapper');

        // Use merges here in case others symbols files depend on this running first,
        // but fail to declare the dependency with a require().
        modulemapper.merges('cordova', 'cordova');
        modulemapper.clobbers('cordova/exec', 'cordova.exec');
        modulemapper.clobbers('cordova/exec', 'Cordova.exec');

    });

    // file: lib/common/utils.js
    define("cordova/utils", function (require, exports, module) {

        var utils = exports;

        /**
         * Defines a property getter / setter for obj[key].
         */
        utils.defineGetterSetter = function (obj, key, getFunc, opt_setFunc) {
            if (Object.defineProperty) {
                var desc = {
                    get: getFunc,
                    configurable: true
                };
                if (opt_setFunc) {
                    desc.set = opt_setFunc;
                }
                Object.defineProperty(obj, key, desc);
            } else {
                obj.__defineGetter__(key, getFunc);
                if (opt_setFunc) {
                    obj.__defineSetter__(key, opt_setFunc);
                }
            }
        };

        /**
         * Defines a property getter for obj[key].
         */
        utils.defineGetter = utils.defineGetterSetter;

        utils.arrayIndexOf = function (a, item) {
            if (a.indexOf) {
                return a.indexOf(item);
            }
            var len = a.length;
            for (var i = 0; i < len; ++i) {
                if (a[i] == item) {
                    return i;
                }
            }
            return -1;
        };

        /**
         * Returns whether the item was found in the array.
         */
        utils.arrayRemove = function (a, item) {
            var index = utils.arrayIndexOf(a, item);
            if (index != -1) {
                a.splice(index, 1);
            }
            return index != -1;
        };

        utils.typeName = function (val) {
            return Object.prototype.toString.call(val).slice(8, -1);
        };

        /**
         * Returns an indication of whether the argument is an array or not
         */
        utils.isArray = function (a) {
            return utils.typeName(a) == 'Array';
        };

        /**
         * Returns an indication of whether the argument is a Date or not
         */
        utils.isDate = function (d) {
            return utils.typeName(d) == 'Date';
        };

        /**
         * Does a deep clone of the object.
         */
        utils.clone = function (obj) {
            if (!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {
                return obj;
            }

            var retVal, i;

            if (utils.isArray(obj)) {
                retVal = [];
                for (i = 0; i < obj.length; ++i) {
                    retVal.push(utils.clone(obj[i]));
                }
                return retVal;
            }

            retVal = {};
            for (i in obj) {
                if (!(i in retVal) || retVal[i] != obj[i]) {
                    retVal[i] = utils.clone(obj[i]);
                }
            }
            return retVal;
        };

        /**
         * Returns a wrapped version of the function
         */
        utils.close = function (context, func, params) {
            if (typeof params == 'undefined') {
                return function () {
                    return func.apply(context, arguments);
                };
            } else {
                return function () {
                    return func.apply(context, params);
                };
            }
        };

        /**
         * Create a UUID
         */
        utils.createUUID = function () {
            return UUIDcreatePart(4) + '-' +
                UUIDcreatePart(2) + '-' +
                UUIDcreatePart(2) + '-' +
                UUIDcreatePart(2) + '-' +
                UUIDcreatePart(6);
        };

        /**
         * Extends a child object from a parent object using classical inheritance
         * pattern.
         */
        utils.extend = (function () {
            // proxy used to establish prototype chain
            var F = function () { };
            // extend Child from Parent
            return function (Child, Parent) {
                F.prototype = Parent.prototype;
                Child.prototype = new F();
                Child.__super__ = Parent.prototype;
                Child.prototype.constructor = Child;
            };
        }());

        /**
         * Alerts a message in any available way: alert or console.log.
         */
        utils.alert = function (msg) {
            if (window.alert) {
                window.alert(msg);
            } else if (console && console.log) {
                console.log(msg);
            }
        };


        //------------------------------------------------------------------------------
        function UUIDcreatePart(length) {
            var uuidpart = "";
            for (var i = 0; i < length; i++) {
                var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
                if (uuidchar.length == 1) {
                    uuidchar = "0" + uuidchar;
                }
                uuidpart += uuidchar;
            }
            return uuidpart;
        }


    });

    window.cordova = require('cordova');
    // file: lib/scripts/bootstrap.js

    (function (context) {
        if (context._cordovaJsLoaded) {
            throw new Error('cordova.js included multiple times.');
        }
        context._cordovaJsLoaded = true;

        var channel = require('cordova/channel');
        var pluginloader = require('cordova/pluginloader');

        var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];

        function logUnfiredChannels(arr) {
            for (var i = 0; i < arr.length; ++i) {
                if (arr[i].state != 2) {
                    console.log('Channel not fired: ' + arr[i].type);
                }
            }
        }

        window.setTimeout(function () {
            if (channel.onDeviceReady.state != 2) {
                console.log('deviceready has not fired after 5 seconds.');
                logUnfiredChannels(platformInitChannelsArray);
                logUnfiredChannels(channel.deviceReadyChannelsArray);
            }
        }, 5000);

        // Replace navigator before any modules are required(), to ensure it happens as soon as possible.
        // We replace it so that properties that can't be clobbered can instead be overridden.
        function replaceNavigator(origNavigator) {
            var CordovaNavigator = function () { };
            CordovaNavigator.prototype = origNavigator;
            var newNavigator = new CordovaNavigator();
            // This work-around really only applies to new APIs that are newer than Function.bind.
            // Without it, APIs such as getGamepads() break.
            if (CordovaNavigator.bind) {
                for (var key in origNavigator) {
                    if (typeof origNavigator[key] == 'function') {
                        newNavigator[key] = origNavigator[key].bind(origNavigator);
                    }
                }
            }
            return newNavigator;
        }
        if (context.navigator) {
            context.navigator = replaceNavigator(context.navigator);
        }

        // _nativeReady is global variable that the native side can set
        // to signify that the native code is ready. It is a global since
        // it may be called before any cordova JS is ready.
        if (window._nativeReady) {
            channel.onNativeReady.fire();
        }

        /**
         * Create all cordova objects once native side is ready.
         */
        channel.join(function () {
            // Call the platform-specific initialization
            require('cordova/platform').initialize();

            // Fire event to notify that all objects are created
            channel.onCordovaReady.fire();

            // Fire onDeviceReady event once page has fully loaded, all
            // constructors have run and cordova info has been received from native
            // side.
            // This join call is deliberately made after platform.initialize() in
            // order that plugins may manipulate channel.deviceReadyChannelsArray
            // if necessary.
            channel.join(function () {
                require('cordova').fireDocumentEvent('deviceready');
            }, channel.deviceReadyChannelsArray);

        }, platformInitChannelsArray);

        // Don't attempt to load when running unit tests.
        if (typeof XMLHttpRequest != 'undefined') {
            pluginloader.load();
        }
    }(window));

    // file: lib/scripts/bootstrap-android.js

    // Tell the native code that a page change has occurred.
    require('cordova/exec')(null, null, 'PluginManager', 'startup', []);
    require('cordova/channel').onNativeReady.fire();

})();
